package haust;

import static org.lwjgl.openal.AL10.*;
import static org.lwjgl.opengl.GL11.*;

import java.util.ArrayList;
import org.lwjgl.input.Keyboard;
import org.lwjgl.input.Mouse;
import org.lwjgl.opengl.Display;
import org.newdawn.slick.opengl.Texture;

/**
 * DemoScene is a very basic 3D scene to demonstrate stereorendering and one way to handle sound-fx<br/>
 * <br/>
 * This scene has a simple scene containing 3 models and a sound that is relative to the listener (camera).<br\>
 * <br/>
 * There's one sound being played, which is set to be relative to the listener<br/>
 * When the listener is inside the house, the volume of the soundsource is lowered to simulate an indoor environment<br/>
 * <br/>
 * Keys used:<br/>
 * WASD to move around and hold right mouse button to rotate camera<br/>
 * F1 - normal rendering<br/>
 * F2 - anaglyph rendering<br/>
 * F3 - passive stereorendering<br/> 
 * 
 */
public class DemoScene implements Client
{
	private Camera cam;
	
	private SoundSource srcRain;
	private SoundSource srcFire;
	
	private Texture ground;
	
	//Skyboxtextures
	private Texture skyRight;
	private Texture skyLeft;
	private Texture skyTop;
	private Texture skyFront;
	private Texture skyBack;


	private SceneObject house;	
	private ArrayList<SceneObject> sceneObjects = new ArrayList<SceneObject>();
	

	private Vec4 ambient = new Vec4(0.6f, 0.6f, 0.6f, 1.0f);
	private Vec4 diffuse = new Vec4(0.5f, 0.5f, 0.5f, 1.0f);
	private Vec4 position = new Vec4(0,5,0,1);
	
	
	private int num = 5500;
	private float xVals[];
	private float yVals[];
	private float zVals[];
	
	private float yVel[];
	private java.util.Random rng;
	private float sceneSize = 50.0f;
	
	private int renderMode = Entry.RENDER_NORMAL;
	private boolean insideHouse = false;
	
	@Override
	public int Initialize()  {
		cam = new Camera();
		
		TextureManager.addTexture("grasstile.png");
		TextureManager.addTexture("coveredwell_diffuse.png");
		TextureManager.addTexture("pine_green.jpg");
		TextureManager.addTexture("house.jpg");
		
		TextureManager.addTexture("galaxy/galaxy+X.png");
		TextureManager.addTexture("galaxy/galaxy+Y.png");
		TextureManager.addTexture("galaxy/galaxy+Z.png");
		TextureManager.addTexture("galaxy/galaxy-X.png");
		TextureManager.addTexture("galaxy/galaxy-Y.png");
		TextureManager.addTexture("galaxy/galaxy-Z.png");
		TextureManager.addTexture("barkbase00.jpg");
		TextureManager.addTexture("lamppost_diffuse.png");
		TextureManager.addTexture("flare.png");
		
		ground = TextureManager.getTextureByName("grasstile.png");		
		skyRight = TextureManager.getTextureByName("galaxy/galaxy+X.png");
		skyLeft = TextureManager.getTextureByName("galaxy/galaxy-X.png");
		skyTop = TextureManager.getTextureByName("galaxy/galaxy+Y.png");
		skyFront = TextureManager.getTextureByName("galaxy/galaxy-Z.png");
		skyBack = TextureManager.getTextureByName("galaxy/galaxy+Z.png");
		
		
		ModelManager.addModel("house.hmdl");
		ModelManager.addModel("firepit.hdml");
		ModelManager.addModel("campfire.hdml");
		ModelManager.addModel("fence.hmdl");
		ModelManager.addModel("post.hdml");
		ModelManager.addModel("well.hdml");
		
		house = ModelManager.createNewObject("house.hmdl");
		house.setScale(0.5f);
		house.setPosition(5,0,5);
		house.setTexture(TextureManager.getTextureByName("house.jpg"));
		house.flipYZ();
		house.calcBounds();
		sceneObjects.add(house);
		
		SceneObject fence = ModelManager.createNewObject("fence.hmdl");
		fence.setScale(0.3f);
		fence.setTexture(TextureManager.getTextureByName("pine_green.jpg"));
		sceneObjects.add(fence);
		
		SceneObject post = ModelManager.createNewObject("post.hdml");
		post.setPosition(4,0,-5);
		post.setScale(0.1f);
		post.setRotation(-90, 1,0,0);
		post.setTexture(TextureManager.getTextureByName("lamppost_diffuse.png"));
		sceneObjects.add(post);
		
		SceneObject well = ModelManager.createNewObject("well.hdml");
		well.setScale(0.8f);
		well.setTexture(TextureManager.getTextureByName("coveredwell_diffuse.png"));
		well.setPosition(0,0,-5);		
		sceneObjects.add(well);
		
		SoundManager.addSound("hardrain.wav");
		srcRain = SoundManager.createNewSource("hardrain.wav");
		
		alSourcei(srcRain.getSourceID(), AL_SOURCE_RELATIVE, AL_TRUE);
		srcRain.setPos( new Vec3(0,5,0));
		srcRain.update();

		alSourcePlay(srcRain.getSourceID());
		
		
		glEnable(GL_LIGHTING);
		glEnable(GL_LIGHT0);
		
		glLight(GL_LIGHT0, GL_AMBIENT, ambient.get() );
		glLight(GL_LIGHT0, GL_DIFFUSE, diffuse.get() );
		glLight(GL_LIGHT0, GL_POSITION, position.get() );
		
		glLightf(GL_LIGHT0, GL_LINEAR_ATTENUATION, 0.01f);
		glLightf(GL_LIGHT0, GL_QUADRATIC_ATTENUATION, 0.01f);
		glLightf(GL_LIGHT0, GL_CONSTANT_ATTENUATION, 1.0f);

		
		
		//Setup Particles
		rng = new java.util.Random();
		
		xVals = new float[num];
		yVals = new float[num];
		zVals = new float[num];
		
		yVel = new float[num];
		
		for( int i = 0; i < num; ++i )
		{
			xVals[i] = -sceneSize + 2*sceneSize * rng.nextFloat(); 
			yVals[i] =  sceneSize * rng.nextFloat(); 
			zVals[i] = -sceneSize + 2*sceneSize * rng.nextFloat();
			
			yVel[i] = 0.5f + rng.nextFloat() * 5.0f;
		}
		
		return 1;
	}

	@Override
	public void Deinitialize() {
		SoundManager.removeSource(srcFire);
		SoundManager.removeSource(srcRain);
		
		ModelManager.destroy();
	}

	@Override
	public void Update(float fDelta) {
		if( Keyboard.isKeyDown(Keyboard.KEY_F1) ) renderMode = Entry.RENDER_NORMAL;
		if( Keyboard.isKeyDown(Keyboard.KEY_F2) ) renderMode = Entry.RENDER_3D_REDBLUE;
		if( Keyboard.isKeyDown(Keyboard.KEY_F3) ) renderMode = Entry.RENDER_3D_PASSIVE;
		
		
		if( Mouse.isButtonDown(1) ) //1 = Right Mouse Button
		{
			if( Mouse.isGrabbed() == false )
				Mouse.setGrabbed(true);
			else
				cam.rotate(Mouse.getDX(), Mouse.getDY() );
		}
		else if( Mouse.isGrabbed() )
			Mouse.setGrabbed(false);
	
		
		cam.move( Keyboard.KEY_W,Keyboard.KEY_S, Keyboard.KEY_A, Keyboard.KEY_D );
		
		
		//Update Particles
		/* Foreach particle
		 *   move downwards
		 *   if y < 0.0f
		 *     reset to a new random position
		 */
		for( int i = 0; i < num; ++i )
		{
			yVals[i] -= 1.5f*yVel[i] * fDelta;
			//Accelerate velocity by 1 per second
			yVel[i] += fDelta;
			
			if( yVals[i] <= 0.0f )
			{
				xVals[i] = rng.nextFloat() * 2*sceneSize - sceneSize;
				zVals[i] = rng.nextFloat() * 2*sceneSize - sceneSize;
				yVals[i] = sceneSize;
				
				yVel[i] = rng.nextFloat() * 5.0f + 0.5f;
			}
		}
		
		
		insideHouse = house.isInsideBounds(cam.pos);
		
		if( insideHouse )
			alSourcef( srcRain.getSourceID(), AL_GAIN, 0.2f);
		else
			alSourcef( srcRain.getSourceID(), AL_GAIN, 1.0f);
	}	
	
	
	@Override
	public void Render() {
		if( renderMode == Entry.RENDER_NORMAL )
			cam.lookAt();
		else
			cam.lookAt( Entry.eye_seperation );

		
		if( Keyboard.isKeyDown(Keyboard.KEY_E)) {
			position.setX(cam.pos.getX());
			position.setY(cam.pos.getY());
			position.setZ(cam.pos.getZ());
		}
		
		glLight(GL_LIGHT0, GL_POSITION, position.get() );


		 
		if( Keyboard.isKeyDown(Keyboard.KEY_SPACE) ) {
		    glBegin(GL_LINES);
		   
		    for( float val = -sceneSize; val <= sceneSize; val+=1.0f)
		    {
		    	glVertex3f(val, 0.1f, -sceneSize);
		    	glVertex3f(val, 0.1f,  sceneSize);
		    	
		    	glVertex3f(-sceneSize, 0.1f, val);
		    	glVertex3f( sceneSize, 0.1f, val);
		    }
		    glEnd();
		}
		
		glEnable(GL_LIGHTING);
		glEnable(GL_LIGHT0);

		glColor3f(1,1,1);

		for( int i = 0; i < sceneObjects.size(); ++i )
			sceneObjects.get(i).render();
	
		
		//Draw grassy ground	  
	    ground.bind();
	    glBegin(GL_QUADS);
	    glNormal3f(0,1,0);	    	
	    for( int z = -25; z < 25; ++z ) {
	    	for( int x = -25; x < 25; ++x ) {
	    		float tcX = (x+25) / 2.0f;
	    		float tcZ = (z+25) / 2.0f;
	    		glTexCoord2f(tcX, tcZ); glVertex3f(x,0,z);
	    		glTexCoord2f(tcX+0.5f, tcZ); glVertex3f(x+1,0,z);
	    		glTexCoord2f(tcX+0.5f, tcZ+0.5f); glVertex3f(x+1,0,z+1);
	    		glTexCoord2f(tcX, tcZ+0.5f); glVertex3f(x,0,z+1);
	    	}
	    }
	    glEnd();
	    
	    glDisable(GL_TEXTURE_2D);
		glDisable(GL_LIGHTING);
		glDisable(GL_BLEND);  
		
		//Rain
		glEnable(GL_BLEND);
		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
		glColor4f(0.2f, 0.2f, 0.3f,1.0f);
		glBegin(GL_LINES);
			for( int i = 0; i < num; ++i )
			{
				glVertex3f(xVals[i], yVals[i]-0.15f, zVals[i]);
				glVertex3f(xVals[i], yVals[i]+0.15f, zVals[i]);
			}
		glEnd();
		

		
		glPushMatrix();
			float cval = 1.0f;
			glColor4f(cval,cval,cval,1);
			glTranslatef(0,10,0);
			glScalef(100.0f,100.0f,100.0f);
			drawSkyBox();
		glPopMatrix();
		
	
		glPointSize(5.0f);
		glDisable(GL_TEXTURE_2D);
		glColor3f(1,1,1);
		glBegin(GL_POINTS);
			glVertex3f(position.getX(), position.getY(), position.getZ());
		glEnd();
		glPointSize(1.0f);
	
		
		Entry.pushOrtho();
		
			//Crosshair
			glDisable(GL_TEXTURE_2D);
			glDisable(GL_DEPTH_TEST);
			glLineWidth(2.0f);
			
			glColor3f(1,1,1);
			if( insideHouse )
				glColor3f(1,0,0);
			
			glBegin(GL_LINES);
				int w = Display.getWidth() >> 1;
				int h = Display.getHeight() >> 1;
				glVertex2f(w-6, h);glVertex2f(w-12, h);
				glVertex2f(w+6, h);glVertex2f(w+12, h);
			glEnd();
			glEnable(GL_DEPTH_TEST);
			glLineWidth(1.0f);
			FontManager.drawTextFont(getClass().getSimpleName(), Display.getWidth()*0.05f, Display.getHeight()*0.95f);
			
			//reset color to white
			glColor3f(1,1,1);
		Entry.popOrtho();
	}
	
	
	private void drawSkyBox()
	{
		glColor3f(0.3f, 0.3f, 0.3f);
		glEnable(GL_TEXTURE_2D);
		skyLeft.bind();
		glBegin(GL_QUADS);
			glTexCoord2f(0,0); glVertex3f(-sceneSize, -10.0f, -sceneSize);
			glTexCoord2f(1,0); glVertex3f(-sceneSize, -10.0f,  sceneSize);
			glTexCoord2f(1,1); glVertex3f(-sceneSize,  50.0f,  sceneSize);
			glTexCoord2f(0,1); glVertex3f(-sceneSize,  50.0f, -sceneSize);
		glEnd();
		
		skyRight.bind();
		glBegin(GL_QUADS);
			glTexCoord2f(0,0); glVertex3f( sceneSize, -10.0f, -sceneSize);
			glTexCoord2f(1,0); glVertex3f( sceneSize, -10.0f,  sceneSize);
			glTexCoord2f(1,1); glVertex3f( sceneSize,  50.0f,  sceneSize);
			glTexCoord2f(0,1); glVertex3f( sceneSize,  50.0f, -sceneSize);
		glEnd();
		
		skyBack.bind();
		glBegin(GL_QUADS);
			glTexCoord2f(1,1); glVertex3f(-sceneSize, -10.0f,  sceneSize);
			glTexCoord2f(1,0); glVertex3f( sceneSize, -10.0f,  sceneSize);
			glTexCoord2f(0,0); glVertex3f( sceneSize,  50.0f,  sceneSize);
			glTexCoord2f(0,1); glVertex3f(-sceneSize,  50.0f,  sceneSize);
		glEnd();
		
		skyFront.bind();
		glBegin(GL_QUADS);
			glTexCoord2f(1,1); glVertex3f(-sceneSize, -10.0f, -sceneSize);
			glTexCoord2f(1,0); glVertex3f( sceneSize, -10.0f, -sceneSize);
			glTexCoord2f(0,0); glVertex3f( sceneSize,  50.0f, -sceneSize);
			glTexCoord2f(0,1); glVertex3f(-sceneSize,  50.0f, -sceneSize);
		glEnd();
		
		skyTop.bind();
		glBegin(GL_QUADS);
			glTexCoord2f(1,1); glVertex3f(-sceneSize,  50.0f, -sceneSize);
			glTexCoord2f(1,0); glVertex3f(-sceneSize,  50.0f,  sceneSize);
			glTexCoord2f(0,0); glVertex3f( sceneSize,  50.0f,  sceneSize);
			glTexCoord2f(0,1); glVertex3f( sceneSize,  50.0f, -sceneSize);
		glEnd();
		glDisable(GL_TEXTURE_2D);
		glColor3f(1,1,1);
	}

	@Override
	public int getRenderMode() {
		return renderMode;
	}

	@Override
	public boolean getExitFlag() {
		return Keyboard.isKeyDown(Keyboard.KEY_ESCAPE);
	}
}